package easypal.brilliard.world.brilliards.communication.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;

import easypal.brilliard.util.TraceUtil;
import easypal.brilliard.world.brilliards.communication.CommunicationChannel;
import easypal.brilliard.world.brilliards.communication.CommunicationException;

public class CommunicationChannelSocketImpl implements CommunicationChannel {
	protected Socket socket;
	protected Writer out;
	protected BufferedReader in;

	public CommunicationChannelSocketImpl(Socket socket) {
		this.socket = socket;
	}
	
	@Override
	public void init() throws CommunicationException {
		
		try {
			out = new OutputStreamWriter(socket.getOutputStream());
	        in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
	        
		} catch (IOException ex) {
			String exceptionMessage = "communication channel can't open the streams.";
			TraceUtil.trace(this, exceptionMessage);
			
			/* If it is corrupted, then destroy it.*/
			this.destroy();
			
			throw new CommunicationException(exceptionMessage, ex);
		}

		
	}

	@Override
	public void send(String message) throws CommunicationException {
		//TraceUtil.trace(this, "Begin send message.");
		try {
			out.write(message, 0, message.length());
			out.flush();
		} catch (IOException ex) {
			String exceptionMessage = "communication channel sending message fails.";
			TraceUtil.trace(this, exceptionMessage);
			
			/* If it is corrupted, then destroy it.*/
			this.destroy();
			
			throw new CommunicationException(exceptionMessage, ex);
		}
		//TraceUtil.trace(this, "End send message.");
	}

	@Override
	public String receive() throws CommunicationException {
		//TraceUtil.trace(this, "Begin receive message.");
		StringBuffer message = new StringBuffer("");
		try {
			String line = in.readLine();
			//TraceUtil.trace(this, "Receive first line of message");
			while (line != null && !line.equals("")) {
				message.append(line + "\r\n");
				line = in.readLine();
			}
		} catch (IOException ex) {
			
			String exceptionMessage = "communication channel receiving message fails.";
			TraceUtil.trace(this, exceptionMessage);
			
			/* If it is corrupted, then destroy it.*/
			this.destroy();
			
			throw new CommunicationException(exceptionMessage, ex);
		} finally {
			
		}
		
		//TraceUtil.trace(this, "End receive message: " + message);
		
		return message.toString();
	}

	@Override
	public void destroy() {
			/* Close output stream first. */
			try {
				if (out != null) {
					out.close();
				}
				
			} catch (IOException ex) {
				/* Destruction is enforced regardless of any exception. */
				String exceptionMessage = "communication channel output stream closing fails.";
				TraceUtil.trace(this, exceptionMessage);
			} finally {
				out = null;
			}
			
			/* Second, close the input stream. */
			try {
				if (in != null) {
					in.close();
				}
				
			} catch (IOException ex) {
				/* Destruction is enforced regardless of any exception. */
				String exceptionMessage = "communication channel input stream closing fails.";
				TraceUtil.trace(this, exceptionMessage);
			} finally {
				in = null;
			}
			
			/* Last, close the socket */
			try {
				if (socket != null) {
					socket.close();
				}
				
			} catch (IOException ex) {
				/* Destruction is enforced regardless of any exception. */
				String exceptionMessage = "communication channel  closing socket fails.";
				TraceUtil.trace(this, exceptionMessage);
			} finally {
				socket = null;
			}
	}

}
